#include "../include/soundplayer.h"
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <lame/lame.h>

#define MP3_FRAME_SIZE 1152
#define RAWSIZE MP3_FRAME_SIZE*2

environment_t env;

void pcm_combine_channels(short* pcml, short* pcmr, short* stereo){
	//interleave the channels
	unsigned long x, counter;
	counter = 0;
	for (x = 0; x <= RAWSIZE; x += 2){
		stereo[x] = pcml[counter];
		stereo[x+1] = pcmr[counter];
		counter++;
	}
}

size_t get_id3tag_size(unsigned char* buffer){
	struct _id3tag {
		unsigned char magic[4];
		uint16_t version;
		char flags;
		uint32_t size;
	} id3tag;
	unsigned long retval, x = 0;
	while (x < env->size){
		if (buffer[x] == 0x49){
			if (buffer[x+1] == 0x44){
				if (buffer[x+2] == '3'){
					break;
				}
			}
		}
		++x;
	}
	if (x == env->size){
		//assume that the whole file was parsed with no match
		retval = 0;
	}
	else {
		id3tag.size = (buffer[x+9])|(buffer[x+8]<<7)|(buffer[x+7]<<14)|(buffer[x+6]<<21);
		retval = (id3tag.size < env->size) ? id3tag.size+10 : 0;
	}
	env->message("id3tag size = %lu\n", retval);
	return retval;
}
void play_mp3(FILE* input){
	//start a lame instance
	if(env->status != SP_IDLE) return; //assume the soundplayer is busy, or broken and exit
	env->status = SP_PLAY;
	lame_t lame = lame_init();
	hip_t l = hip_decode_init();
	lame_init_params(lame);
	lame_set_decode_only(lame, 1);   //set decode only

	//making buffers
	short pcml[MP3_FRAME_SIZE*2];
	short pcmr[MP3_FRAME_SIZE*2];
	short output[RAWSIZE*2];
	char syncword[3] = { 0xFF, 0xFB, 0x00 };
	//static const char *syncword = "\xFF\xFB";

	//setting up mp3data_struct
	mp3data_struct mp3info;

	unsigned char* mp3 =  (unsigned char*) malloc(env->size);

	unsigned long offset = 0;


	unsigned long readbytes;
	int status, rc, first_time = 1;
	unsigned long frames_decoded = 0;
	int totalframes = 0;

	do {
		if (env->status == SP_ERROR) break; //so the decoder can attempt to exit gracefully
		readbytes = fread(mp3, 1, env->size, input);
		if (env->noid3 == 0 && first_time){
			first_time--;
			offset = get_id3tag_size(mp3);
		}

		mp3info.totalframes = 0; //clear this field
		status = hip_decode1_headers(l, mp3 + offset, env->size - offset, pcml, pcmr, &mp3info);
		//do analasys after first frame decode
		if(FLAGUNSET(SP_OVERRIDE_HERTZ)) 
			if(mp3info.header_parsed && mp3info.samplerate != 0) env->rate = mp3info.samplerate;
		if(FLAGUNSET(SP_OVERRIDE_CHANNEL)) //this returns 0 usually for some reason
			if(mp3info.header_parsed && mp3info.stereo != 0) env->channels = mp3info.stereo;

		if ( env->progress != NULL ) {
			if(mp3info.totalframes)
				totalframes = mp3info.totalframes;
			else
				totalframes = nstringfind((char *) mp3 + offset, syncword, env->size-offset); //minimize cpu requirements when no progress
		}

		pcm_output_configure();

		frames_decoded++;
		if (env->isfifo == 1) {
			free(mp3); //free up more ram
			mp3 = NULL; //so i don't error
		}
		pcm_combine_channels(pcml, pcmr, output);

		do {
			while(env->status == SP_PAUSE) sleep(1); //block if the status is SP_PAUSE

			rc = pcm_output_write(output, status);
			if (rc == 0){
				status = hip_decode1_headers(l, NULL, 0, pcml, pcmr, &mp3info);
				if (env->progress != NULL) env->progress(frames_decoded, totalframes);
				pcm_combine_channels(pcml, pcmr, output);
				frames_decoded++;
			}

		}
		while ((env->status < SP_STOP && status > 0) || frames_decoded < 10);
	}
	while (env->status < SP_STOP && env->isfifo == 2 && readbytes == env->size);

	//end a lame instance
	free(mp3); //if not freed, free
	hip_decode_exit(l);   //exit hip decoder instance l
	lame_close(lame);   //exit lame instance lame
	env->status = SP_IDLE; //all errors have by now been handled and we've left the soundplayer in a usable state
}
